#include "record.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define PCM_FORMAT SND_PCM_FORMAT_S16_LE // PCM格式：16位小端

/**
 * 清理资源并安全退出程序
 * @param context: 音频捕捉上下文
 */
void audio_record_cleanup(audio_record_context_t *context)
{
    if (context->buffer)
    {
        free(context->buffer); // 释放缓冲区
        context->buffer = NULL;
    }
    if (context->output_file)
    {
        fclose(context->output_file); // 关闭文件
        context->output_file = NULL;
    }
    if (context->pcm_handle)
    {
        snd_pcm_drain(context->pcm_handle); // 清空PCM捕捉缓冲区
        snd_pcm_close(context->pcm_handle); // 关闭PCM设备
        context->pcm_handle = NULL;
    }
    free(context); // 释放上下文结构体
    printf("Record Complete!\n");
}

/**
 * 配置PCM设备参数
 * @param context: 音频捕捉上下文
 * @param pcm_device: PCM设备名称
 * @param channels: 声道数
 * @param sample_rate: 采样率
 */
static int audio_record_configure_pcm(audio_record_context_t *context, const char *pcm_device, unsigned int channels, unsigned int sample_rate)
{
    int err;
    snd_pcm_hw_params_t *hw_params;
    unsigned int rate = sample_rate;
    int dir;
    unsigned int actual_rate;

    // 打开PCM设备用于音频捕捉
    if ((err = snd_pcm_open(&context->pcm_handle, pcm_device, SND_PCM_STREAM_CAPTURE, 0)) < 0)
    {
        fprintf(stderr, "Error opening PCM device %s: %s\n", pcm_device, snd_strerror(err));
        return err;
    }

    // 分配硬件参数对象
    snd_pcm_hw_params_alloca(&hw_params);

    // 初始化硬件参数结构体的默认值
    if ((err = snd_pcm_hw_params_any(context->pcm_handle, hw_params)) < 0)
    {
        fprintf(stderr, "Cannot initialize hardware parameter structure: %s\n", snd_strerror(err));
        return err;
    }

    // 设置访问类型为交错模式
    if ((err = snd_pcm_hw_params_set_access(context->pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
    {
        fprintf(stderr, "Error setting access type: %s\n", snd_strerror(err));
        return err;
    }

    // 设置PCM数据格式
    if ((err = snd_pcm_hw_params_set_format(context->pcm_handle, hw_params, PCM_FORMAT)) < 0)
    {
        fprintf(stderr, "Error setting format: %s\n", snd_strerror(err));
        return err;
    }

    // 设置声道数
    if ((err = snd_pcm_hw_params_set_channels(context->pcm_handle, hw_params, channels)) < 0)
    {
        fprintf(stderr, "Error setting channels: %s\n", snd_strerror(err));
        return err;
    }

    // 设置采样率
    if ((err = snd_pcm_hw_params_set_rate_near(context->pcm_handle, hw_params, &rate, &dir)) < 0)
    {
        fprintf(stderr, "Error setting sample rate: %s\n", snd_strerror(err));
        return err;
    }

    // 设置硬件参数
    if ((err = snd_pcm_hw_params(context->pcm_handle, hw_params)) < 0)
    {
        fprintf(stderr, "Error setting hardware parameters: %s\n", snd_strerror(err));
        return err;
    }

    // 获取周期大小（帧数）
    snd_pcm_hw_params_get_period_size(hw_params, &context->period_size, &dir);

    // 获取实际的采样率
    snd_pcm_hw_params_get_rate(hw_params, &actual_rate, &dir);

    // 为捕获数据分配缓冲区
    context->buffer = (char *)malloc(snd_pcm_frames_to_bytes(context->pcm_handle, context->period_size));
    if (!context->buffer)
    {
        fprintf(stderr, "Cannot allocate buffer\n");
        return -ENOMEM;
    }

    // 打印当前参数
    printf("PCM Device: %s\n", pcm_device);
    printf("Channels: %u\n", channels);
    printf("Sample Rate: %u Hz\n", actual_rate);
    printf("Period Size: %lu frames\n", context->period_size);

    return 0;
}

/**
 * 打开输出文件
 * @param context: 音频捕捉上下文
 * @param filename: 输出文件名称
 */
static int audio_record_open_output_file(audio_record_context_t *context, const char *filename)
{
    context->output_file = fopen(filename, "wb");
    if (!context->output_file)
    {
        fprintf(stderr, "Cannot open output file\n");
        return -ENOENT;
    }
    return 0;
}

/**
 * 录音线程函数
 * @param arg: 音频捕捉上下文
 */
static void *audio_record_thread(void *arg)
{
    audio_record_context_t *context = (audio_record_context_t *)arg;
    printf("Recording... Press Ctrl+C to stop.\n");
    while (context->recording)
    {
        int pcm = snd_pcm_readi(context->pcm_handle, context->buffer, context->period_size);
        if (pcm == -EPIPE)
        {
            fprintf(stderr, "Overrun occurred\n");
            snd_pcm_prepare(context->pcm_handle); // 准备PCM设备
        }
        else if (pcm < 0)
        {
            fprintf(stderr, "Error reading from PCM device: %s\n", snd_strerror(pcm));
            context->recording = 0; // 停止录音
        }
        else
        {
            fwrite(context->buffer, snd_pcm_frames_to_bytes(context->pcm_handle, pcm), 1, context->output_file);
        }
    }
    return NULL;
}

/**
 * 开始录音
 * @param context: 音频捕捉上下文
 */
void audio_record_start(audio_record_context_t *context)
{
    if (context->recording)
    {
        printf("Recording is already in progress.\n");
        return;
    }
    context->recording = 1; // 设置录音标志位
    pthread_create(&context->thread, NULL, audio_record_thread, context);
}

/**
 * 停止录音
 * @param context: 音频捕捉上下文
 */
void audio_record_stop(audio_record_context_t *context)
{
    if (!context->recording)
    {
        printf("Recording is not in progress.\n");
        return;
    }
    context->recording = 0; // 清除录音标志位
    pthread_join(context->thread, NULL);
    if (context->output_file)
    {
        fclose(context->output_file); // 关闭文件
        context->output_file = NULL;
    }
}

/**
 * 初始化音频捕捉
 * @param pcm_device: PCM设备名称
 * @param channels: 声道数
 * @param sample_rate: 采样率
 * @param filename: 输出文件名称
 * @return: 音频捕捉上下文
 */
audio_record_context_t *audio_record_init(const char *pcm_device, unsigned int channels, unsigned int sample_rate, const char *filename)
{
    // 分配音频捕捉上下文结构体
    audio_record_context_t *context = (audio_record_context_t *)malloc(sizeof(audio_record_context_t));
    if (!context)
    {
        fprintf(stderr, "Cannot allocate audio_record_context_t\n");
        return NULL;
    }

    // 初始化上下文的成员变量
    context->pcm_handle = NULL;
    context->output_file = NULL;
    context->buffer = NULL;
    context->period_size = 0;
    context->recording = 0;

    // 配置PCM设备参数
    if (audio_record_configure_pcm(context, pcm_device, channels, sample_rate) != 0)
    {
        free(context);
        return NULL;
    }

    return context;
}

/**
 * 重新初始化音频捕捉
 * @param context: 音频捕捉上下文
 * @param pcm_device: PCM设备名称
 * @param channels: 声道数
 * @param sample_rate: 采样率
 * @param filename: 输出文件名称
 */
void audio_record_reinit(audio_record_context_t *context, const char *pcm_device, unsigned int channels, unsigned int sample_rate, const char *filename)
{
    if (context->buffer)
    {
        free(context->buffer); // 释放缓冲区
        context->buffer = NULL;
    }
    if (context->pcm_handle)
    {
        snd_pcm_drain(context->pcm_handle); // 清空PCM捕捉缓冲区
        snd_pcm_close(context->pcm_handle); // 关闭PCM设备
        context->pcm_handle = NULL;
    }

    // 配置PCM设备参数
    if (audio_record_configure_pcm(context, pcm_device, channels, sample_rate) != 0)
    {
        free(context);
        return;
    }

    // 打开输出文件
    if (audio_record_open_output_file(context, filename) != 0)
    {
        audio_record_cleanup(context);
    }
}
